package com.hzhq.contract.service.impl;

import com.hzhq.contract.bean.dto.DepartDTO;
import com.hzhq.contract.bean.dto.UserDTO;
import com.hzhq.contract.bean.entity.Depart;
import com.hzhq.contract.bean.entity.Role;
import com.hzhq.contract.bean.entity.User;
import com.hzhq.contract.bean.entity.UserRole;
import com.hzhq.contract.bean.vo.DepartVO;
import com.hzhq.contract.convert.DepartConvertBasic;
import com.hzhq.contract.convert.UserConvertBasic;
import com.hzhq.contract.repo.*;
import com.hzhq.contract.service.DepartService;
import com.hzhq.contract.status.DefaultValue;
import com.hzhq.contract.status.TypeCode;
import com.hzhq.contract.util.Page2ResultUtil;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import springfox.documentation.oas.mappers.ExamplesMapper;

import javax.validation.groups.Default;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author: hzhq1255
 * @mail: hzhq1255@163.com
 * @date: 2021/4/15 0:15
 * @desc:
 */
@Service
public class DepartServiceImpl implements DepartService {


    @Autowired
    AdminRepository adminRepo;

    @Autowired
    UserRepository userRepo;

    @Autowired
    DepartRepository departRepo;

    @Autowired
    RoleRepository roleRepo;

    @Autowired
    UserRoleRepository userRoleRepo;

    @Autowired
    MongoTemplate mongoTemplate;

    private ObjectId string2ObjectId(String id){
        if (id == null){
            return new ObjectId();
        }
        if (ObjectId.isValid(id)){
            return new ObjectId(id);
        }
        return new ObjectId();
    }

    private List<String> getAdminStringInDepart(Depart depart){
        Optional<Role> roleOptional =  roleRepo.findByRoleCodeAndDeleted(TypeCode.ROLE_TYPE_ADMIN.getCode(), DefaultValue.NOT_DELETED);
        if ( roleOptional.isEmpty() || depart == null){
            return new ArrayList<>();
        }
//        List<UserRole> userRoleList = userRoleRepo.findByDepartAndRoleAndPassedAndDeleted(depart, roleOptional.get(),DefaultValue.PASSED_REVIEW,DefaultValue.NOT_DELETED);

        return null;
    }

    @Override
    public List<String> getAdminListByDepartName(String departName) {
        Optional<Depart> departOptional = departRepo.findByDepartNameAndDeleted(departName, DefaultValue.NOT_DELETED);
        return getAdminStringInDepart(departOptional.orElse(null));
    }

    @Override
    public List<String> getAdminListByDepartId(String departId) {
        Optional<Depart> departOptional = departRepo.findByDepartIdAndDeleted(departId, DefaultValue.NOT_DELETED);
        return getAdminStringInDepart(departOptional.orElse(null));
    }

    @Override
    public Page<DepartDTO> searchAllPageByQuery(Query query, Integer currentPage, Integer pageSize) {
        Pageable pageable = Page2ResultUtil.buildPageableByParam(currentPage, pageSize, Sort.by(Sort.Direction.DESC, Depart.DEPART_ID_FIELD));
        long count = mongoTemplate.count(query, Depart.class);
        List<Depart> departs = mongoTemplate.find(query.with(pageable), Depart.class);
        List<DepartDTO> departDTOS = departs.stream().map(DepartConvertBasic.INSTANCE::poToDto).collect(Collectors.toList());
        return new PageImpl<>(departDTOS, pageable, count);
    }

    @Override
    public DepartDTO getOneByDepartId(String departId) {
        Depart depart = departRepo.findByDepartIdAndAndDeleted(string2ObjectId(departId),DefaultValue.NOT_DELETED).orElse(null);
        return DepartConvertBasic.INSTANCE.poToDto(depart);
    }

    @Override
    public DepartDTO getOneByDepartName(String departName) {
        Depart depart = departRepo.findByDepartNameAndDeleted(departName,DefaultValue.NOT_DELETED).orElse(null);
        //System.out.println(departName);
        return DepartConvertBasic.INSTANCE.poToDto(depart);
    }

    @Override
    public List<DepartDTO> getAllList() {
        List<Depart> departList = departRepo.findByDeleted(DefaultValue.NOT_DELETED);
        return departList.stream().map(DepartConvertBasic.INSTANCE::poToDto).collect(Collectors.toList());
    }

    @Override
    public Page<DepartDTO> getAllPage(Integer currentPage, Integer pageSize) {
        Pageable pageable = Page2ResultUtil.buildPageableByParam(currentPage, pageSize, Sort.by(Sort.Direction.DESC,"departId"));
        Page<Depart> departPage = departRepo.findByDeleted(DefaultValue.NOT_DELETED,pageable);
        return departPage.map(DepartConvertBasic.INSTANCE::poToDto);
    }

    private Boolean isDepartExisted(String departName){
        Optional<Depart> departOptional = departRepo.findByDepartNameAndDeleted(departName,DefaultValue.NOT_DELETED);
        return departOptional.isPresent();
    }

    @Override
    public DepartDTO save(DepartDTO departDTO) {
        Depart depart = departRepo.save(DepartConvertBasic.INSTANCE.dtoToPo(departDTO));
        return DepartConvertBasic.INSTANCE.poToDto(depart);
    }

    @Override
    public List<DepartDTO> saveAll(List<DepartDTO> departDTOList) {
        for (DepartDTO departDTO: departDTOList){
            if (isDepartExisted(departDTO.getDepartName())){
                return null;
            }
        }
        List<Depart> departList = departRepo.saveAll(departDTOList.stream().map(DepartConvertBasic.INSTANCE::dtoToPo).collect(Collectors.toList()));
        return departList.stream().map(DepartConvertBasic.INSTANCE::poToDto).collect(Collectors.toList());
    }

    @Override
    public DepartDTO deleteByDepartName(String departName) {
        Optional<Depart> departOptional = departRepo.findByDepartNameAndDeleted(departName,DefaultValue.NOT_DELETED);
        if (departOptional.isPresent()){
            Depart depart = departOptional.get();
            depart.setDeleted(DefaultValue.DELETED);
            return DepartConvertBasic.INSTANCE.poToDto(departRepo.save(depart));
        }
        return null;
    }

    @Override
    public DepartDTO deleteByDepartId(String departId) {
        Optional<Depart> departOptional = departRepo.findByDepartIdAndAndDeleted(string2ObjectId(departId),DefaultValue.NOT_DELETED);
        if (departOptional.isPresent()){
            Depart depart = departOptional.get();
            depart.setDeleted(DefaultValue.DELETED);
            return DepartConvertBasic.INSTANCE.poToDto(departRepo.save(depart));
        }
        return null;
    }

    private Depart delDepart(Depart depart){
        if (depart == null){
            return new Depart();
        }
        depart.setDeleted(DefaultValue.DELETED);
        return depart;
    }

    @Override
    public List<DepartDTO> deleteAllByIds(List<String> departIds) {
        List<ObjectId> objectIds = departIds.stream().map(ObjectId::new).collect(Collectors.toList());
        List<Depart> departList = departRepo.findByDepartIdInAndDeleted(objectIds,DefaultValue.NOT_DELETED);
        List<Depart> departDelList = departList.stream().map(this::delDepart).collect(Collectors.toList());
        return departRepo.saveAll(departDelList).stream().map(DepartConvertBasic.INSTANCE::poToDto).collect(Collectors.toList());
    }

    @Override
    public Page<DepartDTO> searchAllPages(DepartDTO departDTO, Integer currentPage, Integer pageSize) {
        Depart depart = DepartConvertBasic.INSTANCE.dtoToPo(departDTO);
        depart.setDeleted(DefaultValue.NOT_DELETED);
        Pageable pageable = Page2ResultUtil.buildPageableByParam(currentPage, pageSize,
                Sort.by(Sort.Direction.DESC,"departId"));
        ExampleMatcher exampleMatcher = ExampleMatcher.matching()
                .withMatcher("departName", ExampleMatcher.GenericPropertyMatchers.contains())
                .withMatcher("desc",ExampleMatcher.GenericPropertyMatchers.contains());
        Example<Depart> example = Example.of(depart,exampleMatcher);
        return departRepo.findAll(example,pageable).map(DepartConvertBasic.INSTANCE::poToDto);
    }

}
